#!/bin/bash
#
# backup-dirs-s3
#
# Script's documentation page: http://www.adminbuntu.com/backup_directories_to_aws_s3
#
# Backs up one or more directories to an Amazon AWS S3 bucket
#
#
# Copyright 2013 Andrew Ault
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software
# and associated documentation files (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge, publish, distribute,
# sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all copies or
# substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

usage (){
    echo "backup-subdirs-s3"
    echo " "
    echo "Must be run as root because attributes and ownership is preserved in tarballs."
    echo " "
    echo Usage: backup-dirs-s3 directory1 [directory2...] s3destination
    echo Example: sudo backup-dirs-s3 "directory/directory" "directory/another" "s3://destination-bucket"
    echo " "
}

if ! hash generate_rotate_filename 2>/dev/null; then
    echo "ERROR: generate_rotate_filename is required" 1>&2
    exit 1
fi

append=`generate_rotate_filename`
ext=".tgz"
max_tarball_size=2000000000

# only root can run this script
if [ "$(id -u)" != "0" ]; then
    echo "This script must be run as root." 1>&2
    exit 1
fi

# array of all directories to back up with a trailing element containing the destination s3 bucket
directories=(${@})

# if fewer than 2 parameters, show usage
if [ ${#directories[@]} -lt 2 ]; then
    usage
    exit 1
fi

# clip off the s3 destination, retaining the rest of the array as a list of directories to backup
s3_destination=${directories[${#directories[@]} - 1]}
unset directories[${#directories[@]}-1]
directory_count=${#directories[@]}

# iterate directories array
for directory in "${directories[@]}"; do
    if [ $directory = "/" ]; then
        echo "ERROR: Can't backup /" 1>&2
        exit 1
    fi
    
    # check that directory exists
    if [ ! -d $directory ]; then
        echo "ERROR: Specified directory does not exist: $directory" 1>&2
        exit 1
    fi
    
    # change to directory
    echo "directory: ${directory}"
    cd $directory
    
    # get bare name of directory to back up
    bare_directory=${PWD##*/}
    echo "bare_directory: ${bare_directory}"
    
    # create tarball filename and replace spaces with dashes
    tarball_filename=$bare_directory-${append}${ext}
    tarball_filename=${tarball_filename// /-}
    
    cd ..
    parent_directory=`pwd`
    echo "parent_directory: ${parent_directory}"
    
    # create tarball
    echo "creating tarball: ${tarball_filename}"
    tar -pczf $tarball_filename "${bare_directory}"
    
    # limit tarball size uploaded to s3, if too big split tarball into chunks
    # upload result to s3 bucket
    tarball_filesize=$(stat -c%s "$tarball_filename")
    if (( $tarball_filesize > $max_tarball_size )); then
        echo "$tarball_filename is too large to upload to S3 at $tarball_filesize bytes"
        echo "Splitting $tarball_filename into 1Gb chunks"
        split -b1024M $tarball_filename "$tarball_filename-"
        # delete existing split tarballs with this base filename in case the directory is smaller now
        s3cmd del "${tarball_filename}*"
        s3cmd put $tarball_filename* $s3_destination
        rm $tarball_filename* 2> /dev/null
    else
        echo "Uploading $tarball_filename to $s3_destination"
        s3cmd put $tarball_filename $s3_destination
        rm $tarball_filename 2> /dev/null
    fi
    
done